package view;

import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import chess.GroupsHelper;

import model.Location;

/**
 * The main view element, aptly called MainView.  It deals with the majority of user interactions in this program.
 * It contains the program's menubar, board tiles, and message area.
 * @author Ben
 */
@SuppressWarnings("serial")
public class MainView extends JFrame
{
	/**
	 * This is the {@link java.awt.event.ActionListener} for all view elements. Although encapsulated by the Class cast, 
	 * it is actually the controller that is the listener.
	 */
	private ActionListener listener;
	
	/**
	 * This {@link view.GridPanel} is a view component of {@link view.MainView}.
	 * It represents the grid of tiles itself.
	 */
	private GridPanel gridTiles;
	//private MessageField textField;
	
	/**
	 * This {@link view.MessageArea} is a view component of {@link view.MainView}.  
	 * It is a display area for text information thrown by the controller.
	 */
	private MessageArea textArea;
	
	/**
	 * This {@link view.MenuBar} is the menubar for {@link view.MainView}.
	 */
	private MenuBar menuBar;
	
	/**
	 * This {@link view.Skin} is a system for updating the graphics of 
	 * {@link view.MainView} depending on themes selected by the user.
	 */
	private Skin skin;
	
	/**
	 * This constructor initializes a new MainView, which is the central view component for chess.
	 * It builds the view with a default set of themes that can be edited at any time.
	 * The default themes are actually settings stored in a text file which are read in by {@link chess.GroupsHelper}.
	 * @param listener - the {@link java.awt.event.ActionListener} that receives the view's {@link java.awt.event}
	 * @param defaultSkinFile - the path for a text file containing {@link view.Skin} settings
	 * @param visible - determines whether or not the view should be visible when constructed.
	 */
	public MainView(ActionListener listener, String defaultSkinFile, boolean visible)
	{
		this.listener = listener;
		
		ArrayList<String>[][] defaultSkin = GroupsHelper.importData(defaultSkinFile);
		skin = new Skin(defaultSkin[0][0].get(0), defaultSkin[0][1].get(0), defaultSkin[0][2].get(0), defaultSkin[0][3].get(0));
		
		newView(visible);
	}
	
	/**
	 * This method takes Integer commands in order to modify the look of the game via Skin updating.
	 * @param item - the internal view element to be modified
	 * @param change - the command instructing the skin to change to a selected theme.
	 */
	public void changeDisplaySettings(int item, int change)
	{
		switch(item) {
			case 1: setSkin(Integer.toString(change), skin.getBlack(), skin.getBackground(), skin.getHighlight());
					break;
			case 2: setSkin(skin.getWhite(), Integer.toString(change), skin.getBackground(), skin.getHighlight());
					break;
			case 3: setSkin(skin.getWhite(), skin.getBlack(), Integer.toString(change), skin.getHighlight());
					break;
			case 4: setSkin(skin.getWhite(), skin.getBlack(), skin.getBackground(), Integer.toString(change));
					break;
		}
	}
	
	/**
	 * This method does the actual work of setting up a a new {@link view.MainView}.
	 * @param visible - determines whether the view will be visible or not.
	 */
	private void newView(boolean visible)
	{
		gridTiles = new GridPanel(skin, (MouseListener)listener);
		//textField = new MessageField();
		textArea = new MessageArea();
		menuBar = new MenuBar();
		
		this.setTitle("Chess by Sacha Best, Brian Bagdasarian, & Ben Vigman");
		this.setLayout(new GridBagLayout());
		this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		GridBagConstraints tileConstraints = new GridBagConstraints(0, 0, GridBagConstraints.REMAINDER, 1, 0.8, 0.8, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0 ,0), 20, 20);
		
		this.setPreferredSize(new Dimension(600,720));
		this.setMinimumSize(new Dimension(600,720));
		this.setSize(this.getPreferredSize());
		Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
		int xPos = (screen.width / 2) - (this.getWidth() / 2); // Center horizontally.
		int yPos = (screen.height / 2) - (this.getHeight() / 2); // Center vertically.
		this.setLocation(xPos, yPos);
		this.setJMenuBar(menuBar);
		this.add(gridTiles, tileConstraints);
        //add(textField, textField.getConstraint());
        add(textArea.getScrollPane(), textArea.getConstraint());
		
		for(int x = 0; x < this.getJMenuBar().getMenuCount(); x++)
			for(int y = 0; y < this.getJMenuBar().getMenu(x).getItemCount(); y++)
				this.getJMenuBar().getMenu(x).getItem(y).addActionListener(listener);
		
		//textField.addActionListener(listener);
		
		invalidate();
		validate();
		repaint();
		this.setVisible(visible);
	}
	
	/**
	 * This method moves a graphical element from one tile to another.
	 * The element may be null, a white piece, or a black piece.
	 * @param from - From location
	 * @param to - To location
	 */
	public void movePiece(Location from, Location to)
	{
		int[] piece = gridTiles.getPiece(from);
		int pieceType = piece[0];
		int color = piece[1];
		
		gridTiles.setPiece(from, -1, color);
		gridTiles.setPiece(to, pieceType, color);
	}
	
	/**
	 * This method throws a {@link javax.swing.JOptionPane} at the user to request input for a pawn promotion.
	 * @return - the Integer representation of the user selection.
	 */
	public int askForPromotion()
	{
		Object[] options = {"Bishop", "Knight", "Rook", "Queen"};
		int n = JOptionPane.showOptionDialog(this, "What would you like to promote the pawn to?",
				"Promotion", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[3]);
		switch (n)
		{
		case 0:
			return pieces.Piece.BISHOP;
		case 1:
			return pieces.Piece.KNIGHT;
		case 2:
			return pieces.Piece.ROOK;
		case 3:
			return pieces.Piece.QUEEN;
		}
		return 0;
	}
	
	/**
	 * This method sets a graphical element at a location on the board.
	 * The element may be null, a white piece, or a black piece.
	 * @param loc - Location to set
	 * @param piece - Integer representation of element to set.
	 * @param color - Integer representation of black or white.
	 */
	public void setPiece(Location loc, int piece, int color)
	{
		gridTiles.setPiece(loc, piece, color);
	}
	
	/**
	 * This method displays text in {@link view.MainView}'s textArea.
	 * @param input - String to display
	 */
	public void displayText(String input)
	{
		textArea.append(input + "\n");
		textArea.setCaretPosition(textArea.getDocument().getLength());
	}
	
	/**
	 * This method highlights the background of tiles on the board.
	 * @param locs - Location of tiles to highlight
	 * @param active - Boolean signifying whether to turn highlighting on or off
	 */
	public void highlight(ArrayList<Location> locs, boolean active)
	{
		if(locs == null)
			return;
		for(Location loc : locs)
			gridTiles.highlight(loc, active);
	}
	
	/**
	 * This method resets a new skin for the view. 
	 * Enables view to update graphical elements based on user input.
	 * @param white - String representation of white theme
	 * @param black - String representation of black theme
	 * @param background - String representation of background theme
	 * @param highlight - String representation of highlight theme
	 */
	public void setSkin(String white, String black, String background, String highlight)
	{
		skin = new Skin(white, black, background, highlight);
		gridTiles.setSkin(skin);
	}

	/**
	 * This method throws new {@link javax.swing.JFileChooser} at the user. Allows user to select a save file.
	 * @return - String path for game to be loaded.
	 */
	public String showFileChooser()
	{
		String path = getClass().getClassLoader().getResource(".").getPath();
		path = path.substring(0,path.indexOf("bin"));
		path += "Saves";
		File file = new File(path);
		JFileChooser chooser = new JFileChooser(file);
		chooser.setFileFilter(new FileNameExtensionFilter("Chess Saves", "sav"));
		chooser.setDialogTitle("Load");
		int choice = chooser.showOpenDialog(this);
		if (choice == JFileChooser.APPROVE_OPTION)
			return chooser.getSelectedFile().toString();
		return null;	
	}
	
	/**
	 * This method clears all text in the textArea.
	 */
	public void clearText() 
	{
		textArea.setText(null);
	}
	
	/**
	 * This method plays a soundFX for the program
	 * @param soundFile - File path for the soundFX to be played.
	 */
	public void playFX(String soundFile)
    {
    	try 
    	{
    		File file = new File("sounds/" + soundFile);
    		AudioInputStream audioIn = AudioSystem.getAudioInputStream(file);
    		Clip clip = AudioSystem.getClip();
    		clip.open(audioIn);
    		clip.start();
    		} 
    	catch (UnsupportedAudioFileException e) {
    		JOptionPane.showMessageDialog(this, "Unsupported Audio, please reload program");
    		System.exit(0);
    		} 
    	catch (IOException e) {
    		JOptionPane.showMessageDialog(this, "Audio file not read, please reload program");
    		System.exit(0);
    		} 
    	catch (LineUnavailableException e) {
    		e.printStackTrace();
    		}
    }
}
